package com.gusto.engine.neighborhood.aspects;

import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Configurable;

import com.gusto.engine.beans.model.Res;
import com.gusto.engine.colfil.Prediction;
import com.gusto.engine.colfil.Rating;
import com.gusto.engine.semsim.service.SimilarityService;

/**
 * <p>This aspect intercepts events of the {@link SimilarityService}.<br/>
 * Whenever a similarity is calculated it is saved in the persistent storage.<br/> 
 * Or when we detect that a context configuration has changed,
 * we have to remove all calculated distances.</p>
 * 
 * @author amokrane.belloui@gmail.com
 *
 */
@Aspect
@Configurable
public class StoreDistanceAspect {
	
	private Logger log = Logger.getLogger(getClass());
	
	public StoreDistanceAspect() {
		super();
	}
	
	public StoreDistanceAspect(String title) {
		super();
	}
	
	private com.gusto.engine.semsim.neighborhood.SemEventListener semanticEventListener;
	public void setSemanticEventListener(com.gusto.engine.semsim.neighborhood.SemEventListener semanticEventListener) {
		this.semanticEventListener = semanticEventListener;
	}
	
	private com.gusto.engine.colfil.neighborhood.ColEventListener collaborativeEventListener;
	public void setCollaborativeEventListener(com.gusto.engine.colfil.neighborhood.ColEventListener collaborativeEventListener) {
		this.collaborativeEventListener = collaborativeEventListener;
	}
	
	/**
	 * When a similarity is calculated
	 * @param context
	 * @param resource1
	 * @param resource2
	 * @param ret
	 */
	@AfterReturning(pointcut="execution(* com.gusto.engine.semsim.service.SimilarityService.getSimilarity(..)) && args(context, resource1, resource2)", 
			        returning="ret")
	public void similarityCalculated(String context, Res resource1, Res resource2, Double ret) {
		Double sim = ret;
		log.debug("Intercepred a similarity calculation ctx:" + context + ", " + resource1 + "-" + resource2 + ", Similarity: " + sim);
		if (semanticEventListener != null) {
			semanticEventListener.similarityCalculated(context, resource1, resource2, sim);
		}
	}
	
	/**
	 * When a context configuration has changed
	 * @param context
	 * @throws Throwable
	 */
	@After("execution(* com.gusto.engine.semsim.service.SimilarityService.contextConfigChanged(..)) && args(context)")
    public void contextConfigChanged(String context) throws Throwable {
		log.info("Context Config change detected for context: " + context);
		
		if (semanticEventListener != null) {
			semanticEventListener.contextConfigChanged(context);
			log.info("Context Config change processed for context: " + context);
		}
	}
	
	
	
	/**
	 * When a rating is inserted
	 * @param userId
	 * @param itemId
	 * @param rating
	 * @param checkExistence
	 * @throws Throwable
	 */
	@After("execution(* com.gusto.engine.colfil.service.CollaborativeService.insertRating(..)) && args(userId, itemId, rating, checkExistence)")
    public void ratingInserted(long userId, long itemId, Rating rating, boolean checkExistence) throws Throwable {
		log.info("Rating '" + rating + "' added ... ");
		
		if (collaborativeEventListener != null) {
			log.info("Process Rating " + rating);
			collaborativeEventListener.ratingInserted(userId, itemId, rating, checkExistence);
		}
	}
	
	/**
	 * When a prediction is inserted
	 * @param userId
	 * @param itemId
	 * @param prediction
	 * @throws Throwable
	 */
	@Deprecated
	@After("execution(* com.gusto.engine.colfil.service.CollaborativeService.insertPrediction(..)) && args(userId, itemId, prediction)")
    public void predictionInserted(long userId, long itemId, Prediction prediction) throws Throwable {
		log.info("Prediction '" + prediction + "' added ... ");
		
		if (collaborativeEventListener != null) {
			log.info("Process Prediction " + prediction);
			collaborativeEventListener.predictionInserted(userId, itemId, prediction);
		}
	}
	
}
